```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Java HashMap深度解析 - 技术小馆</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            background-color: #f9fafb;
            color: #1f2937;
            line-height: 1.6;
        }
        .hero {
            background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
            color: white;
            border-radius: 0 0 2rem 2rem;
        }
        .hero-title {
            font-family: 'Noto Serif SC', serif;
            text-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .hero-subtitle {
            font-weight: 300;
            opacity: 0.9;
        }
        .code-block {
            background-color: #1e293b;
            color: #e2e8f0;
            border-radius: 0.5rem;
            font-family: 'Courier New', Courier, monospace;
        }
        .code-keyword {
            color: #f472b6;
        }
        .code-comment {
            color: #94a3b8;
            font-style: italic;
        }
        .code-string {
            color: #86efac;
        }
        .code-number {
            color: #fbbf24;
        }
        .code-type {
            color: #60a5fa;
        }
        .section-title {
            border-left: 4px solid #4f46e5;
            padding-left: 1rem;
            font-family: 'Noto Serif SC', serif;
        }
        .card {
            transition: all 0.3s ease;
            background: white;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
        }
        .card:hover {
            transform: translateY(-2px);
            box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
        }
        .tip-card {
            border-left: 4px solid #10b981;
        }
        .warning-card {
            border-left: 4px solid #f59e0b;
        }
        .danger-card {
            border-left: 4px solid #ef4444;
        }
        .footer {
            background-color: #111827;
            color: #9ca3af;
        }
        .footer a:hover {
            color: #e5e7eb;
        }
        .mermaid {
            background: white;
            padding: 1rem;
            border-radius: 0.5rem;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            margin: 1rem 0;
        }
        .drop-cap:first-letter {
            float: left;
            font-size: 3.5rem;
            line-height: 3rem;
            padding-top: 0.5rem;
            padding-right: 0.5rem;
            font-family: 'Noto Serif SC', serif;
            font-weight: bold;
            color: #4f46e5;
        }
    </style>
</head>
<body class="antialiased">
    <!-- Hero Section -->
    <section class="hero py-16 md:py-24 px-4 md:px-8">
        <div class="container mx-auto max-w-6xl">
            <div class="flex flex-col items-center text-center">
                <span class="text-indigo-200 text-sm mb-4 font-medium tracking-wider"><i class="fas fa-code mr-2"></i>JAVA COLLECTION FRAMEWORK</span>
                <h1 class="hero-title text-4xl md:text-5xl font-bold mb-6">深入解析HashMap</h1>
                <p class="hero-subtitle text-xl md:text-2xl max-w-3xl mb-8">从数据结构到实现原理，全面掌握Java最常用的集合类</p>
                <div class="flex space-x-4">
                    <a href="#structure" class="px-6 py-3 bg-white text-indigo-600 font-medium rounded-full hover:bg-indigo-50 transition-all">
                        <i class="fas fa-project-diagram mr-2"></i>数据结构
                    </a>
                    <a href="#implementation" class="px-6 py-3 bg-indigo-700 text-white font-medium rounded-full hover:bg-indigo-800 transition-all">
                        <i class="fas fa-microscope mr-2"></i>实现原理
                    </a>
                </div>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <div class="container mx-auto max-w-6xl px-4 md:px-8 py-12">
        <!-- Introduction -->
        <section class="mb-16">
            <p class="drop-cap text-gray-700 text-lg leading-relaxed mb-6">
                HashMap是Java程序员最常用的集合类之一，它提供了键值对的存储方式，并且支持常数时间级别的查找、插入和删除操作。作为Java集合框架中的核心成员，HashMap不仅在日常开发中应用广泛，也是面试中的高频考点。
            </p>
            <p class="text-gray-700 text-lg leading-relaxed mb-6">
                然而，很多开发者虽然经常使用HashMap，却对其内部实现机制知之甚少。特别是其哈希碰撞处理和扩容机制，往往是理解HashMap性能特性和正确使用姿势的关键。
            </p>
        </section>

        <!-- Chapter 1 -->
        <section id="structure" class="mb-20">
            <h2 class="section-title text-3xl font-bold mb-8">1. HashMap的基础结构</h2>
            
            <div class="grid md:grid-cols-2 gap-8 mb-12">
                <div class="card p-6 rounded-lg">
                    <h3 class="text-2xl font-semibold mb-4 text-indigo-600">1.1 类继承关系</h3>
                    <p class="text-gray-700 mb-4">让我们从HashMap的类定义开始了解它的基础结构：</p>
                    <div class="code-block p-4 mb-4 overflow-x-auto">
                        <pre><code><span class="code-keyword">public class</span> <span class="code-type">HashMap</span>&lt;K,V&gt; <span class="code-keyword">extends</span> <span class="code-type">AbstractMap</span>&lt;K,V&gt;
    <span class="code-keyword">implements</span> <span class="code-type">Map</span>&lt;K,V&gt;, <span class="code-type">Cloneable</span>, <span class="code-type">Serializable</span> {
    <span class="code-comment">// 实现代码</span>
}</code></pre>
                    </div>
                    <p class="text-gray-700">从类定义中可以看出：</p>
                    <ul class="list-disc pl-6 mt-2 mb-4 space-y-2 text-gray-700">
                        <li>HashMap继承自AbstractMap，获得了Map接口的基本实现</li>
                        <li>实现了Map接口，提供了标准的映射功能</li>
                        <li>实现了Cloneable接口，可以被克隆</li>
                        <li>实现了Serializable接口，可以被序列化</li>
                    </ul>
                </div>

                <div class="card p-6 rounded-lg">
                    <h3 class="text-2xl font-semibold mb-4 text-indigo-600">1.2 核心成员变量</h3>
                    <p class="text-gray-700 mb-4">HashMap的实现依赖于几个关键的成员变量：</p>
                    <div class="code-block p-4 mb-4 overflow-x-auto" style="max-height: 300px;">
                        <pre><code><span class="code-comment">/**
 * 默认初始容量 - 必须是2的幂
 */</span>
<span class="code-keyword">static final</span> <span class="code-keyword">int</span> <span class="code-type">DEFAULT_INITIAL_CAPACITY</span> = 1 &lt;&lt; 4; <span class="code-comment">// 16</span>

<span class="code-comment">/**
 * 最大容量
 */</span>
<span class="code-keyword">static final</span> <span class="code-keyword">int</span> <span class="code-type">MAXIMUM_CAPACITY</span> = 1 &lt;&lt; 30;

<span class="code-comment">/**
 * 默认负载因子
 */</span>
<span class="code-keyword">static final</span> <span class="code-keyword">float</span> <span class="code-type">DEFAULT_LOAD_FACTOR</span> = 0.75f;

<span class="code-comment">/**
 * 链表转红黑树的阈值
 */</span>
<span class="code-keyword">static final</span> <span class="code-keyword">int</span> <span class="code-type">TREEIFY_THRESHOLD</span> = 8;

<span class="code-comment">/**
 * 红黑树转链表的阈值
 */</span>
<span class="code-keyword">static final</span> <span class="code-keyword">int</span> <span class="code-type">UNTREEIFY_THRESHOLD</span> = 6;

<span class="code-comment">/**
 * 转换为红黑树的最小表容量
 */</span>
<span class="code-keyword">static final</span> <span class="code-keyword">int</span> <span class="code-type">MIN_TREEIFY_CAPACITY</span> = 64;

<span class="code-comment">/**
 * 存储数据的数组
 */</span>
<span class="code-keyword">transient</span> <span class="code-type">Node</span>&lt;K,V&gt;[] table;

<span class="code-comment">/**
 * 键值对数量
 */</span>
<span class="code-keyword">transient</span> <span class="code-keyword">int</span> size;

<span class="code-comment">/**
 * 修改次数，用于快速失败机制
 */</span>
<span class="code-keyword">transient</span> <span class="code-keyword">int</span> modCount;

<span class="code-comment">/**
 * 扩容阈值，当size超过此值时进行扩容
 */</span>
<span class="code-keyword">int</span> threshold;

<span class="code-comment">/**
 * 负载因子
 */</span>
<span class="code-keyword">final</span> <span class="code-keyword">float</span> loadFactor;</code></pre>
                    </div>
                </div>
            </div>

            <div class="card p-6 rounded-lg mb-8">
                <h3 class="text-2xl font-semibold mb-4 text-indigo-600">1.3 Node内部类解析</h3>
                <p class="text-gray-700 mb-4">HashMap使用Node类表示键值对节点：</p>
                <div class="code-block p-4 mb-6 overflow-x-auto">
                    <pre><code><span class="code-keyword">static class</span> <span class="code-type">Node</span>&lt;K,V&gt; <span class="code-keyword">implements</span> <span class="code-type">Map.Entry</span>&lt;K,V&gt; {
    <span class="code-keyword">final int</span> hash;
    <span class="code-keyword">final</span> K key;
    V value;
    <span class="code-type">Node</span>&lt;K,V&gt; next;

    <span class="code-type">Node</span>(<span class="code-keyword">int</span> hash, K key, V value, <span class="code-type">Node</span>&lt;K,V&gt; next) {
        <span class="code-keyword">this</span>.hash = hash;
        <span class="code-keyword">this</span>.key = key;
        <span class="code-keyword">this</span>.value = value;
        <span class="code-keyword">this</span>.next = next;
    }

    <span class="code-comment">// 方法实现...</span>
}</code></pre>
                </div>
                <p class="text-gray-700 mb-4">在JDK 8中，还增加了TreeNode类来支持红黑树结构：</p>
                <div class="code-block p-4 mb-4 overflow-x-auto">
                    <pre><code><span class="code-keyword">static final class</span> <span class="code-type">TreeNode</span>&lt;K,V&gt; <span class="code-keyword">extends</span> <span class="code-type">LinkedHashMap</span>.<span class="code-type">Entry</span>&lt;K,V&gt; {
    <span class="code-type">TreeNode</span>&lt;K,V&gt; parent;  <span class="code-comment">// 父节点</span>
    <span class="code-type">TreeNode</span>&lt;K,V&gt; left;    <span class="code-comment">// 左子节点</span>
    <span class="code-type">TreeNode</span>&lt;K,V&gt; right;   <span class="code-comment">// 右子节点</span>
    <span class="code-type">TreeNode</span>&lt;K,V&gt; prev;    <span class="code-comment">// 前一个节点</span>
    <span class="code-keyword">boolean</span> red;           <span class="code-comment">// 节点颜色</span>
    <span class="code-comment">// 方法实现...</span>
}</code></pre>
                </div>
                <p class="text-gray-700">这些内部类构成了HashMap的底层数据结构：一个Node数组，每个槽位可能是一个链表或红黑树（JDK 8）。</p>
            </div>

            <div class="mermaid">
                graph TD
                    A[HashMap] --> B[数组 table]
                    B --> C[Node 链表]
                    B --> D[TreeNode 红黑树]
                    C --> E[Node1]
                    C --> F[Node2]
                    D --> G[TreeNode1]
                    D --> H[TreeNode2]
                    style A fill:#f5f3ff,stroke:#7c3aed
                    style B fill:#ede9fe,stroke:#7c3aed
                    style C,D fill:#ddd6fe,stroke:#7c3aed
                    style E,F,G,H fill:#c4b5fd,stroke:#7c3aed
            </div>
        </section>

        <!-- Chapter 2 -->
        <section id="hashing" class="mb-20">
            <h2 class="section-title text-3xl font-bold mb-8">2. 哈希算法与桶定位</h2>
            
            <div class="card p-6 rounded-lg mb-8">
                <h3 class="text-2xl font-semibold mb-4 text-indigo-600">2.1 hash方法解析</h3>
                <p class="text-gray-700 mb-4">HashMap使用一个自定义的hash方法来计算键的哈希值：</p>
                <div class="code-block p-4 mb-4 overflow-x-auto">
                    <pre><code><span class="code-keyword">static final int</span> hash(<span class="code-type">Object</span> key) {
    <span class="code-keyword">int</span> h;
    <span class="code-keyword">return</span> (key == <span class="code-keyword">null</span>) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}</code></pre>
                </div>
                <p class="text-gray-700 mb-2">这个方法看似简单，但包含了重要的设计思想：</p>
                <ol class="list-decimal pl-6 mb-4 space-y-2 text-gray-700">
                    <li>对null键的特殊处理，返回0</li>
                    <li>将键的hashCode与其高16位进行XOR操作</li>
                </ol>
                <p class="text-gray-700">第二点特别重要，它被称为"扰动函数"，目的是使哈希值的高位也能参与到最终的桶索引计算中，减少哈希冲突。因为在计算桶索引时，只会使用哈希值的低位（例如，容量为16时，只使用低4位），这种设计使得即使键的hashCode低位相同但高位不同，也能映射到不同的桶。</p>
            </div>

            <div class="grid md:grid-cols-2 gap-8 mb-8">
                <div class="card p-6 rounded-lg">
                    <h3 class="text-2xl font-semibold mb-4 text-indigo-600">2.2 索引计算方式</h3>
                    <p class="text-gray-700 mb-4">计算键值对在数组中的索引位置使用以下公式：</p>
                    <div class="code-block p-4 mb-4">
                        <pre><code>index = (n - 1) & hash</code></pre>
                    </div>
                    <p class="text-gray-700 mb-4">其中n是数组的长度，hash是键的哈希值。这等价于对n取模（hash % n），但位运算更高效。</p>
                    <p class="text-gray-700">示例：假设数组长度为16，键的哈希值为20</p>
                    <div class="code-block p-4 mt-2">
                        <pre><code>n - 1 = 15 (二进制：1111)
hash = 20 (二进制：10100)
index = 15 & 20 = 4 (二进制：0100)</code></pre>
                    </div>
                </div>

                <div class="card p-6 rounded-lg">
                    <h3 class="text-2xl font-semibold mb-4 text-indigo-600">2.3 为什么要用2的幂作为容量</h3>
                    <p class="text-gray-700 mb-4">HashMap要求容量必须是2的幂，这不是随意的设计，而是经过深思熟虑的选择：</p>
                    <ol class="list-decimal pl-6 space-y-2 text-gray-700">
                        <li>使用位运算替代取模运算：当n是2的幂时，<code>hash % n</code> 等价于 <code>(n - 1) & hash</code>，而位运算比取模运算更高效</li>
                        <li>更均匀的哈希分布：当n为2的幂时，n-1的二进制表示全为1（例如16-1=15，二进制为1111），这使得参与&运算的位数最多，增加了索引的随机性和均匀性</li>
                        <li>方便扩容：扩容时只需将容量翻倍，并且重新计算索引时可以使用优化算法</li>
                    </ol>
                    <div class="mt-4 p-4 bg-indigo-50 rounded-lg">
                        <p class="text-indigo-700"><i class="fas fa-info-circle mr-2"></i>如果使用非2的幂作为容量，会导致某些哈希桶永远不会被使用，造成空间浪费和哈希冲突增加。</p>
                    </div>
                </div>
            </div>
        </section>

        <!-- Chapter 3 -->
        <section id="collision" class="mb-20">
            <h2 class="section-title text-3xl font-bold mb-8">3. 哈希碰撞解决方案</h2>
            <p class="text-gray-700 mb-6">哈希碰撞指不同的键经过哈希计算后，映射到同一个数组位置。HashMap通过链表和红黑树两种数据结构来解决冲突。</p>
            
            <div class="grid md:grid-cols-2 gap-8 mb-8">
                <div class="card p-6 rounded-lg">
                    <h3 class="text-2xl font-semibold mb-4 text-indigo-600">3.1 JDK 7中的链表实现</h3>
                    <p class="text-gray-700 mb-4">在JDK 7中，HashMap使用拉链法解决哈希冲突：</p>
                    <div class="code-block p-4 mb-4 overflow-x-auto">
                        <pre><code><span class="code-keyword">void</span> addEntry(<span class="code-keyword">int</span> hash, K key, V value, <span class="code-keyword">int</span> bucketIndex) {
    <span class="code-keyword">if</span> ((size >= threshold) && (<span class="code-keyword">null</span> != table[bucketIndex])) {
        resize(2 * table.length);
        hash = (<span class="code-keyword">null</span> != key) ? hash(key) : 0;
        bucketIndex = indexFor(hash, table.length);
    }

    createEntry(hash, key, value, bucketIndex);
}

<span class="code-keyword">void</span> createEntry(<span class="code-keyword">int</span> hash, K key, V value, <span class="code-keyword">int</span> bucketIndex) {
    <span class="code-type">Entry</span>&lt;K,V&gt; e = table[bucketIndex];
    table[bucketIndex] = <span class="code-keyword">new</span> <span class="code-type">Entry</span>&lt;&gt;(hash, key, value, e);
    size++;
}</code></pre>
                    </div>
                    <p class="text-gray-700">当发生碰撞时，新节点插入到链表头部（头插法）。这种方式实现简单，但在链表较长时查询性能下降，最坏情况下时间复杂度为O(n)。</p>
                </div>

                <div class="card p-6 rounded-lg">
                    <h3 class="text-2xl font-semibold mb-4 text-indigo-600">3.2 JDK 8中的链表+红黑树结构</h3>
                    <p class="text-gray-700 mb-4">JDK 8对HashMap进行了重要升级，引入了红黑树来优化长链表的性能：</p>
                    <div class="code-block p-4 mb-4 overflow-x-auto" style="max-height: 400px;">
                        <pre><code><span class="code-keyword">final</span> V putVal(<span class="code-keyword">int</span> hash, K key, V value, <span class="code-keyword">boolean</span> onlyIfAbsent,
               <span class="code-keyword">boolean</span> evict) {
    <span class="code-type">Node</span>&lt;K,V&gt;[] tab; <span class="code-type">Node</span>&lt;K,V&gt; p; <span class="code-keyword">int</span> n, i;
    <span class="code-comment">// 初始化桶数组</span>
    <span class="code-keyword">if</span> ((tab = table) == <span class="code-keyword">null</span> || (n = tab.length) == 0)
        n = (tab = resize()).length;
    <span class="code-comment">// 计算索引，如果没有碰撞，直接插入</span>
    <span class="code-keyword">if</span> ((p = tab[i = (n - 1) & hash]) == <span class="code-keyword">null</span>)
        tab[i] = newNode(hash, key, value, <span class="code-keyword">null</span>);
    <span class="code-keyword">else</span> {
        <span class="code-type">Node</span>&lt;K,V&gt; e; K k;
        <span class="code-comment">// 检查第一个节点</span>
        <span class="code-keyword">if</span> (p.hash == hash &&
            ((k = p.key) == key || (key != <span class="code-keyword">null</span> && key.equals(k))))
            e = p;
        <span class="code-comment">// 如果是树节点，使用红黑树的方式插入</span>
        <span class="code-keyword">else if</span> (p <span class="code-keyword">instanceof</span> <span class="code-type">TreeNode</span>)
            e = ((<span class="code-type">TreeNode</span>&lt;K,V&gt;)p).putTreeVal(<span class="code-keyword">this</span>, tab, hash, key, value);
        <span class="code-comment">// 链表情况</span>
        <span class="code-keyword">else</span> {
            <span class="code-keyword">for</span> (<span class="code-keyword">int</span> binCount = 0; ; ++binCount) {
                <span class="code-keyword">if</span> ((e = p.next) == <span class="code-keyword">null</span>) {
                    p.next = newNode(hash, key, value, <span class="code-keyword">null</span>);
                    <span class="code-comment">// 链表长度超过阈值，转换为红黑树</span>
                    <span class="code-keyword">if</span> (binCount >= TREEIFY_THRESHOLD - 1)
                        treeifyBin(tab, hash);
                    <span class="code-keyword">break</span>;
                }
                <span class="code-keyword">if</span> (e.hash == hash &&
                    ((k = e.key) == key || (key != <span class="code-keyword">null</span> && key.equals(k))))
                    <span class="code-keyword">break</span>;
                p = e;
            }
        }
        <span class="code-comment">// 替换已存在的key对应的value</span>
        <span class="code-keyword">if</span> (e != <span class="code-keyword">null</span>) {
            V oldValue = e.value;
            <span class="code-keyword">if</span> (!onlyIfAbsent || oldValue == <span class="code-keyword">null</span>)
                e.value = value;
            afterNodeAccess(e);
            <span class="code-keyword">return</span> oldValue;
        }
    }
    ++modCount;
    <span class="code-comment">// 检查是否需要扩容</span>
    <span class="code-keyword">if</span> (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    <span class="code-keyword">return</span> <span class="code-keyword">null</span>;
}</code></pre>
                    </div>
                </div>
            </div>

            <div class="card p-6 rounded-lg">
                <h3 class="text-2xl font-semibold mb-4 text-indigo-600">3.3 红黑树转换阈值分析</h3>
                <p class="text-gray-700 mb-4">为什么选择8作为链表转红黑树的阈值？这是基于泊松分布统计结果的选择：</p>
                <p class="text-gray-700 mb-4">根据统计，在负载因子为0.75的情况下，单个桶中元素个数为8的概率已经非常小（约为千万分之一），所以链表很少会达到或超过8。将阈值设置为8是为了在极端情况下仍能保证性能。</p>
                <p class="text-gray-700 mb-4">红黑树相比链表具有更好的查询性能（O(log n) vs O(n)），但是维护红黑树的开销也更大。只有当链表足够长，才值得付出这个开销。</p>
                <p class="text-gray-700">而选择6作为红黑树恢复为链表的阈值，是为了避免链表和红黑树之间频繁转换（如果两个阈值相同，可能会在临界点反复转换）。</p>
            </div>

            <div class="mermaid mt-8">
                flowchart LR
                    A[插入元素] --> B{哈希冲突?}
                    B -->|否| C[直接插入数组位置]
                    B -->|是| D{链表长度 < 8?}
                    D -->|是| E[添加到链表尾部]
                    D -->|否| F{数组长度 >= 64?}
                    F -->|是| G[转换为红黑树]
                    F -->|否| H[扩容数组]
                    style A fill:#dbeafe,stroke:#3b82f6
                    style B fill:#bfdbfe,stroke:#3b82f6
                    style C,D,E,F,G,H fill:#93c5fd,stroke:#3b82f6
            </div>
        </section>

        <!-- Chapter 4 -->
        <section id="resize" class="mb-20">
            <h2 class="section-title text-3xl font-bold mb-8">4. 扩容机制详解</h2>
            <p class="text-gray-700 mb-6">HashMap的扩容机制是保证其性能的关键。当HashMap中的元素数量超过负载因子与容量的乘积时，就会触发扩容操作。</p>
            
            <div class="card p-6 rounded-lg mb-8">
                <h3 class="text-2xl font-semibold mb-4 text-indigo-600">4.1 触发条件分析</h3>
                <p class="text-gray-700 mb-4">HashMap在以下两种情况下会触发扩容：</p>
                <ol class="list-decimal pl-6 mb-4 text-gray-700">
                    <li>初始化时，如果使用了无参构造函数，第一次添加元素时会初始化容量为16的数组</li>
                    <li>当前元素数量超过阈值（threshold = capacity * loadFactor）</li>
                </ol>
                <div class="code-block p-4">
                    <pre><code><span class="code-comment">// JDK 8中的resize方法触发逻辑</span>
<span class="code-keyword">if</span> (++size > threshold)
    resize();</code></pre>
                </div>
            </div>

            <div class="card p-6 rounded-lg mb-8">
                <h3 class="text-2xl font-semibold mb-4 text-indigo-600">4.2 重哈希过程</h3>
                <p class="text-gray-700 mb-4">扩容过程涉及创建一个更大的数组（通常是原容量的2倍），并将原数组中的所有元素重新哈希并分配到新数组中。</p>
                <div class="code-block p-4 mb-4 overflow-x-auto" style="max-height: 400px;">
                    <pre><code><span class="code-comment">// JDK 7中的扩容实现</span>
<span class="code-keyword">void</span> resize(<span class="code-keyword">int</span> newCapacity) {
    <span class="code-type">Entry</span>[] oldTable = table;
    <span class="code-keyword">int</span> oldCapacity = oldTable.length;
    
    <span class="code-comment">// 检查是否超过最大容量</span>
    <span class="code-keyword">if</span> (oldCapacity == MAXIMUM_CAPACITY) {
        threshold = <span class="code-type">Integer</span>.MAX_VALUE;
        <span class="code-keyword">return</span>;
    }

    <span class="code-comment">// 创建新数组</span>
    <span class="code-type">Entry</span>[] newTable = <span class="code-keyword">new</span> <span class="code-type">Entry</span>[newCapacity];
    transfer(newTable);
    table = newTable;
    threshold = (<span class="code-keyword">int</span>)(newCapacity * loadFactor);
}

<span class="code-comment">// 将旧表中的所有元素转移到新表中</span>
<span class="code-keyword">void</span> transfer(<span class="code-type">Entry</span>[] newTable) {
    <span class="code-type">Entry</span>[] src = table;
    <span class="code-keyword">int</span> newCapacity = newTable.length;
    <span class="code-keyword">for</span> (<span class="code-keyword">int</span> j = 0; j &lt; src.length; j++) {
        <span class="code-type">Entry</span>&lt;K,V&gt; e = src[j];
        <span class="code-keyword">if</span> (e != <span class="code-keyword">null</span>) {
            src[j] = <span class="code-keyword">null</span>;
            <span class="code-keyword">do</span> {
                <span class="code-type">Entry</span>&lt;K,V&gt; next = e.next;
                <span class="code-comment">// 重新计算索引</span>
                <span class="code-keyword">int</span> i = indexFor(e.hash, newCapacity);
                <span class="code-comment">// 头插法插入新表</span>
                e.next = newTable[i];
                newTable[i] = e;
                e = next;
            } <span class="code-keyword">while</span> (e != <span class="code-keyword">null</span>);
        }
    }
}</code></pre>
                </div>
                <p class="text-gray-700">这个过程的计算复杂度为O(n)，其中n是HashMap中键值对的数量。频繁扩容会影响性能，所以应该尽可能准确地预估容量。</p>
            </div>

            <div class="card p-6 rounded-lg mb-8">
                <h3 class="text-2xl font-semibold mb-4 text-indigo-600">4.3 JDK 8中的优化：位置重计算</h3>
                <p class="text-gray-700 mb-4">JDK 8对扩容算法进行了优化，利用了容量始终为2的幂这一特性，使得元素要么在原位置，要么在原位置加上原容量的位置：</p>
                <div class="code-block p-4 mb-4 overflow-x-auto" style="max-height: 500px;">
                    <pre><code><span class="code-comment">// JDK 8中的resize方法</span>
<span class="code-keyword">final</span> <span class="code-type">Node</span>&lt;K,V&gt;[] resize() {
    <span class="code-type">Node</span>&lt;K,V&gt;[] oldTab = table;
    <span class="code-keyword">int</span> oldCap = (oldTab == <span class="code-keyword">null</span>) ? 0 : oldTab.length;
    <span class="code-keyword">int</span> oldThr = threshold;
    <span class="code-keyword">int</span> newCap, newThr = 0;
    
    <span class="code-comment">// 计算新容量和新阈值</span>
    <span class="code-keyword">if</span> (oldCap > 0) {
        <span class="code-keyword">if</span> (oldCap >= MAXIMUM_CAPACITY) {
            threshold = <span class="code-type">Integer</span>.MAX_VALUE;
            <span class="code-keyword">return</span> oldTab;
        }
        <span class="code-keyword">else if</span> ((newCap = oldCap &lt;&lt; 1) &lt; MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
            newThr = oldThr &lt;&lt; 1; <span class="code-comment">// 新阈值为旧阈值的两倍</span>
    }
    <span class="code-keyword">else if</span> (oldThr > 0) <span class="code-comment">// 使用threshold作为初始容量</span>
        newCap = oldThr;
    <span class="code-keyword">else</span> {               <span class="code-comment">// 使用默认值</span>
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (<span class="code-keyword">int</span>)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    
    <span class="code-keyword">if</span> (newThr == 0) {
        <span class="code-keyword">float</span> ft = (<span class="code-keyword">float</span>)newCap * loadFactor;
        newThr = (newCap &lt; MAXIMUM_CAPACITY && ft &lt; (<span class="code-keyword">float</span>)MAXIMUM_CAPACITY ?
                  (<span class="code-keyword">int</span>)ft : <span class="code-type">Integer</span>.MAX_VALUE);
    }
    threshold = newThr;
    
    <span class="code-comment">// 创建新表并转移元素</span>
    @<span class="code-type">SuppressWarnings</span>({<span class="code-string">"rawtypes"</span>,<span class="code-string">"unchecked"</span>})
    <span class="code-type">Node</span>&lt;K,V&gt;[] newTab = (<span class="code-type">Node</span>&lt;K,V&gt;[])<span class="code-keyword">new</span> <span class="code-type">Node</span>[newCap];
    table = newTab;
    <span class="code-keyword">if</span> (oldTab != <span class="code-keyword">null</span>) {
        <span class="code-keyword">for</span> (<span class="code-keyword">int</span> j = 0; j &lt; oldCap; ++j) {
            <span class="code-type">Node</span>&lt;K,V&gt; e;
            <span class="code-keyword">if</span> ((e = oldTab[j]) != <span class="code-keyword">null</span>) {
                oldTab[j] = <span class="code-keyword">null</span>;
                <span class="code-keyword">if</span> (e.next == <span class="code-keyword">null</span>)
                    newTab[e.hash & (newCap - 1)] = e;
                <span class="code-keyword">else if</span> (e <span class="code-keyword">instanceof</span> <span class="code-type">TreeNode</span>)
                    ((<span class="code-type">TreeNode</span>&lt;K,V&gt;)e).split(<span class="code-keyword">this</span>, newTab, j, oldCap);
                <span class="code-keyword">else</span> { <span class="code-comment">// 链表优化重哈希</span>
                    <span class="code-type">Node</span>&lt;K,V&gt; loHead = <span class="code-keyword">null</span>, loTail = <span class="code-keyword">null</span>;
                    <span class="code-type">Node</span>&lt;K,V&gt; hiHead = <span class="code-keyword">null</span>, hiTail = <span class="code-keyword">null</span>;
                    <span class="code-type">Node</span>&lt;K,V&gt; next;
                    <span class="code-keyword">do</span> {
                        next = e.next;
                        <span class="code-comment">// 原索引</span>
                        <span class="code-keyword">if</span> ((e.hash & oldCap) == 0) {
                            <span class="code-keyword">if</span> (loTail == <span class="code-keyword">null</span>)
                                loHead = e;
                            <span class="code-keyword">else</span>
                                loTail.next = e;
                            loTail = e;
                        }
                        <span class="code-comment">// 原索引+oldCap</span>
                        <span class="code-keyword">else</span> {
                            <span class="code-keyword">if</span> (hiTail == <span class="code-keyword">null</span>)
                                hiHead = e;
                            <span class="code-keyword">else</span>
                                hiTail.next = e;
                            hiTail = e;
                        }
                    } <span class="code-keyword">while</span> ((e = next) != <span class="code-keyword">null</span>);
                    <span class="code-comment">// 原位置放低位链表</span>
                    <span class="code-keyword">if</span> (loTail != <span class="code-keyword">null</span>) {
                        loTail.next = <span class="code-keyword">null</span>;
                        newTab[j] = loHead;
                    }
                    <span class="code-comment">// 原位置+oldCap放高位链表</span>
                    <span class="code-keyword">if</span> (hiTail != <span class="code-keyword">null</span>) {
                        hiTail.next = <span class="code-keyword">null</span>;
                        newTab[j + oldCap] = hiHead;
                    }
                }
            }
        }
    }
    <span class="code-keyword">return</span> newTab;
}</code></pre>
                </div>
                <p class="text-gray-700 mb-2">JDK 8的优化点：</p>
                <ol class="list-decimal pl-6 mb-4 text-gray-700">
                    <li>不需要重新计算哈希值，只需检查哈希值与原容量的按位与结果</li>
                    <li>使用两个链表分别存储在新表的原位置和原位置+oldCap的元素</li>
                    <li>使用尾插法而不是头插法，保持节点的相对顺序，避免并发环境下的链表成环问题</li>
                </ol>
            </div>

            <div class="card p-6 rounded-lg">
                <h3 class="text-2xl font-semibold mb-4 text-indigo-600">4.4 位置重计算的数学原理</h3>
                <p class="text-gray-700 mb-4">为什么扩容后元素要么在原位置，要么在原位置+oldCap？这可以通过数学推导得出：</p>
                <p class="text-gray-700 mb-4">假设原容量为n（2的幂），新容量为2n。对于任意哈希值h：</p>
                <ul class="list-disc pl-6 mb-4 text-gray-700">
                    <li>原索引：h & (n-1)</li>
                    <li>新索引：h & (2n-1)</li>
                </ul>
                <p class="text-gray-700 mb-4">由于n是2的幂，n-1的二进制表示为全1，而2n-1比n-1多一个高位的1。</p>
                <p class="text-gray-700 mb-4">例如，n=16时：</p>
                <ul class="list-disc pl-6 mb-4 text-gray-700">
                    <li>n-1 = 15 (二进制：1111)</li>
                    <li>2n-1 = 31 (二进制：11111)</li>
                </ul>
                <p class="text-gray-700">所以，元素新位置的计算只与哈希值的一个额外位有关：</p>
                <ul class="list-disc pl-6 text-gray-700">
                    <li>如果该位为0，新索引 = 原索引</li>
                    <li>如果该位为1，新索引 = 原索引 + n</li>
                </ul>
                <p class="text-gray-700 mt-4">这种设计极大地简化了扩容过程中的重哈希计算，提高了扩容效率。</p>
            </div>

            <div class="mermaid mt-8">
                flowchart LR
                    A[旧表 容量n] -->|扩容| B[新表 容量2n]
                    B --> C[原位置]
                    B --> D[原位置+n]
                    style A fill:#f0fdf4,stroke:#10b981
                    style B fill:#dcfce7,stroke:#10b981
                    style C,D fill:#bbf7d0,stroke:#10b981
            </div>
        </section>

        <!-- Chapter 5 -->
        <section id="best-practices" class="mb-20">
            <h2 class="section-title text-3xl font-bold mb-8">5. 最佳实践</h2>
            <p class="text-gray-700 mb-6">基于对HashMap源码的深入理解，以下是一些实用建议和常见陷阱的避免方法：</p>
            
            <div class="grid md:grid-cols-2 gap-8 mb-8">
                <div class="tip-card card p-6 rounded-lg">
                    <div class="flex items-start">
                        <div class="flex-shrink-0 h-10 w-10 rounded-full bg-green-100 flex items-center justify-center text-green-500 mr-4">
                            <i class="fas fa-lightbulb text-xl"></i>
                        </div>
                        <div>
                            <h3 class="text-xl font-semibold mb-3 text-green-700">5.1 合理设置初始容量和负载因子</h3>
                            <p class="text-gray-700 mb-2"><strong>最佳实践：</strong></p>
                            <ul class="list-disc pl-6 mb-4 text-gray-700">
                                <li>如果预先知道要存储的元素数量，设置适当的初始容量可以避免扩容带来的性能损失</li>
                                <li>负载因子默认值0.75是空间和时间的良好平衡点，除非有特殊需求，否则不建议修改</li>
                            </ul>
                            <div class="code-block p-4 mb-4">
                                <pre><code><span class="code-comment">// 假设需要存储1000个元素</span>
<span class="code-comment">// 考虑负载因子0.75，至少需要1000/0.75 ≈ 1334的容量</span>
<span class="code-comment">// 向上取最近的2的幂</span>
<span class="code-keyword">int</span> capacity = 2048;
<span class="code-type">HashMap</span>&lt;<span class="code-type">String</span>, <span class="code-type">User</span>&gt; map = <span class="code-keyword">new</span> <span class="code-type">HashMap</span>&lt;&gt;(capacity);</code></pre>
                            </div>
                            <p class="text-gray-700"><strong>需要注意：</strong><br>构造函数中的参数是初始容量，而不是阈值。HashMap会根据初始容量和负载因子计算阈值。</p>
                        </div>
                    </div>
                </div>

                <div class="warning-card card p-6 rounded-lg">
                    <div class="flex items-start">
                        <div class="flex-shrink-0 h-10 w-10 rounded-full bg-yellow-100 flex items-center justify-center text-yellow-500 mr-4">
                            <i class="fas fa-exclamation-triangle text-xl"></i>
                        </div>
                        <div>
                            <h3 class="text-xl font-semibold mb-3 text-yellow-700">5.2 避免可变对象作为键</h3>
                            <p class="text-gray-700 mb-2"><strong>踩坑提示：</strong><br>使用可变对象作为HashMap的键可能导致严重问题，因为如果键对象在放入后被修改，其哈希值可能发生变化，导致无法正确检索到对应的值。</p>
                            <div class="code-block p-4 mb-4">
                                <pre><code><span class="code-comment">// 错误示例</span>
<span class="code-type">HashMap</span>&lt;<span class="code-type">ArrayList</span>&lt;<span class="code-type">String</span>&gt;, <span class="code-type">String</span>&gt; map = <span class="code-keyword">new</span> <span class="code-type">HashMap</span>&lt;&gt;();
<span class="code-type">ArrayList</span>&lt;<span class="code-type">String</span>&gt; key = <span class="code-keyword">new</span> <span class="code-type">ArrayList</span>&lt;&gt;();
key.add(<span class="code-string">"initial"</span>);
map.put(key, <span class="code-string">"value"</span>);

key.add(<span class="code-string">"modified"</span>);  <span class="code-comment">// 修改了键对象</span>
<span class="code-type">String</span> value = map.get(key);  <span class="code-comment">// 可能返回null，因为键的哈希值已变化</span></code></pre>
                            </div>
                            <p class="text-gray-700"><strong>正确做法：</strong></p>
                            <ul class="list-disc pl-6 text-gray-700">
                                <li>使用不可变对象作为键，如String、Integer等</li>
                                <li>如果必须使用自定义类作为键，确保它们是不可变的，或至少保证影响hashCode()和equals()方法的字段是不可变的</li>
                            </ul>
                        </div>
                    </div>
                </div>

                <div class="danger-card card p-6 rounded-lg">
                    <div class="flex items-start">
                        <div class="flex-shrink-0 h-10 w-10 rounded-full bg-red-100 flex items-center justify-center text-red-500 mr-4">
                            <i class="fas fa-bug text-xl"></i>
                        </div>
                        <div>
                            <h3 class="text-xl font-semibold mb-3 text-red-700">5.3 线程安全考虑</h3>
                            <p class="text-gray-700 mb-2"><strong>踩坑提示：</strong><br>HashMap不是线程安全的，多线程环境下使用可能导致数据不一致或死循环（特别是在JDK 7中）。</p>
                            <div class="code-block p-4 mb-4">
                                <pre><code><span class="code-comment">// 线程不安全示例</span>
<span class="code-type">HashMap</span>&lt;<span class="code-type">String</span>, <span class="code-keyword">int</span>&gt; map = <span class="code-keyword">new</span> <span class="code-type">HashMap</span>&lt;&gt;();
<span class="code-comment">// 多线程并发修改</span>

<span class="code-comment">// 线程安全替代方案</span>
<span class="code-type">Map</span>&lt;<span class="code-type">String</span>, <span class="code-keyword">int</span>&gt; synchronizedMap = <span class="code-type">Collections</span>.synchronizedMap(<span class="code-keyword">new</span> <span class="code-type">HashMap</span>&lt;&gt;());
<span class="code-comment">// 或使用</span>
<span class="code-type">ConcurrentHashMap</span>&lt;<span class="code-type">String</span>, <span class="code-keyword">int</span>&gt; concurrentMap = <span class="code-keyword">new</span> <span class="code-type">ConcurrentHashMap</span>&lt;&gt;();</code></pre>
                            </div>
                            <p class="text-gray-700">ConcurrentHashMap是专为并发设计的，在多线程环境下性能优于synchronizedMap。</p>
                        </div>
                    </div>
                </div>

                <div class="tip-card card p-6 rounded-lg">
                    <div class="flex items-start">
                        <div class="flex-shrink-0 h-10 w-10 rounded-full bg-green-100 flex items-center justify-center text-green-500 mr-4">
                            <i class="fas fa-lightbulb text-xl"></i>
                        </div>
                        <div>
                            <h3 class="text-xl font-semibold mb-3 text-green-700">5.4 hashCode与equals的一致性</h3>
                            <p class="text-gray-700 mb-2"><strong>踩坑提示：</strong><br>自定义类作为键时，必须正确覆盖hashCode()和equals()方法，并确保它们的一致性。</p>
                            <div class="code-block p-4 mb-4">
                                <pre><code><span class="code-comment">// 错误示例：只覆盖equals而不覆盖hashCode</span>
<span class="code-keyword">class</span> <span class="code-type">Person</span> {
    <span class="code-keyword">private</span> <span class="code-type">String</span> name;
    <span class="code-keyword">private</span> <span class="code-keyword">int</span> age;
    
    @<span class="code-type">Override</span>
    <span class="code-keyword">public</span> <span class="code-keyword">boolean</span> equals(<span class="code-type">Object</span> obj) {
        <span class="code-comment">// 实现...</span>
    }
    
    <span class="code-comment">// 未覆盖hashCode方法!</span>
}

<span class="code-comment">// 正确示例</span>
<span class="code-keyword">class</span> <span class="code-type">Person</span> {
    <span class="code-keyword">private</span> <span class="code-type">String</span> name;
    <span class="code-keyword">private</span> <span class="code-keyword">int</span> age;
    
    @<span class="code-type">Override</span>
    <span class="code-keyword">public</span> <span class="code-keyword">boolean</span> equals(<span class="code-type">Object</span> obj) {
        <span class="code-comment">// 实现...</span>
    }
    
    @<span class="code-type">Override</span>
    <span class="code-keyword">public</span> <span class="code-keyword">int</span> hashCode() {
        <span class="code-keyword">return</span> <span class="code-type">Objects</span>.hash(name, age);
    }
}</code></pre>
                            </div>
                            <p class="text-gray-700"><strong>equals和hashCode的约定：</strong></p>
                            <ul class="list-disc pl-6 text-gray-700">
                                <li>如果两个对象相等（equals返回true），它们的hashCode必须相同</li>
                                <li>如果两个对象的hashCode相同，它们不一定相等</li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div>

            <div class="card p-6 rounded-lg">
                <div class="flex items-start">
                    <div class="flex-shrink-0 h-10 w-10 rounded-full bg-indigo-100 flex items-center justify-center text-indigo-500 mr-4">
                        <i class="fas fa-tachometer-alt text-xl"></i>
                    </div>
                    <div>
                        <h3 class="text-xl font-semibold mb-3 text-indigo-700">5.5 性能调优与容量规划</h3>
                        <p class="text-gray-700 mb-2"><strong>最佳实践：</strong></p>
                        <ul class="list-disc pl-6 mb-4 text-gray-700">
                            <li>避免过度扩容：合理估计容量，减少扩容次数</li>
                            <li>避免哈希冲突：确保键的hashCode分布均匀</li>
                            <li>避免过大的初始容量：这会浪费内存</li>
                            <li>理解负载因子的影响：较小的负载因子减少冲突但增加空间占用，较大的负载因子节省空间但可能增加冲突</li>
                        </ul>
                        <div class="code-block p-4">
                            <pre><code><span class="code-comment">// 示例：调整负载因子为0.6，更注重查询性能</span>
<span class="code-type">HashMap</span>&lt;<span class="code-type">String</span>, <span class="code-type">User</span>&gt; map = <span class="code-keyword">new</span> <span class="code-type">HashMap</span>&lt;&gt;(1024, 0.6f);</code></pre>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Summary -->
        <section class="mb-20">
            <div class="bg-gradient-to-r from-indigo-500 to-purple-600 rounded-2xl p-8 text-white">
                <div class="max-w-3xl mx-auto text-center">
                    <h2 class="text-3xl font-bold mb-4">HashMap核心要点总结</h2>
                    <p class="text-xl mb-6 opacity-90">通过本文的深入分析，我们总结了HashMap的关键特性与最佳实践：</p>
                    <div class="grid md:grid-cols-3 gap-6">
                        <div class="bg-white bg-opacity-10 p-4 rounded-lg backdrop-blur-sm">
                            <div class="text-4xl mb-3 text-indigo-200"><i class="fas fa-sitemap"></i></div>
                            <h3 class="font-semibold text-lg mb-2">数据结构</h3>
                            <p>数组+链表/红黑树，负载因子0.75，默认容量16</p>
                        </div>
                        <div class="bg-white bg-opacity-10 p-4 rounded-lg backdrop-blur-sm">
                            <div class="text-4xl mb-3 text-indigo-200"><i class="fas fa-bolt"></i></div>
                            <h3 class="font-semibold text-lg mb-2">哈希算法</h3>
                            <p>高位参与运算，减少冲突，2的幂容量优化计算</p>
                        </div>
                        <div class="bg-white bg-opacity-10 p-4 rounded-lg backdrop-blur-sm">
                            <div class="text-4xl mb-3 text-indigo-200"><i class="fas fa-expand"></i></div>
                            <h3 class="font-semibold text-lg mb-2">扩容机制</h3>
                            <p>双倍扩容，JDK8优化位置重计算</p>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </div>

    <!-- Footer -->
    <footer class="footer py-8">
        <div class="container mx-auto max-w-6xl px-4 md:px-8 text-center">
            <div class="text-lg font-medium mb-2">技术小馆</div>
            <div class="text-sm">
                <a href="http://www.yuque.com/jtostring" class="hover:text-white transition-colors">http://www.yuque.com/jtostring</a>
            </div>
        </div>
    </footer>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
    </script>
</body>
</html>
```